<template>
  <base-map />
  <div class="panel">
    <el-button @click="addRiver_normal">普通的加载</el-button>
    <el-button @click="addRiver_bbox">视口裁剪(bbox策略)</el-button>
    <el-button @click="addRiver_manualBbox">视口裁剪(手动)</el-button>
    <el-button @click="addRiver_wfs">视口裁剪(加载wfs)</el-button>
    <el-button @click="remove">移除</el-button>
  </div>
</template>

<script setup>
import * as radash from "radash";

import { Vector as VectorLayer } from "ol/layer";
import { Vector as VectorSource } from "ol/source";
import { GeoJSON } from "ol/format";
import { bbox as bboxStrategy } from "ol/loadingstrategy";

import { containsExtent } from "ol/extent";

import { getExtent } from "@/utils/view";
import BJGrid from "@/data/河流三角网/BJ.json";

let riverLayer, riverSource;

let riverFeatures, riverFeaturesExtent, lastExtent;

// 移除河流图层
function remove() {
  riverLayer && window.map.removeLayer(riverLayer);
}

// 普通正常加载
function addRiver_normal() {
  riverLayer = new VectorLayer({
    source: new VectorSource({
      format: new GeoJSON({
        dataProjection: "EPSG:4547",
        featureProjection: "EPSG:4326",
      }),
      url: "src/assets/geojson/BJ.json",
    }),
  });

  window.map.addLayer(riverLayer);
}

// 按需要加载（只加载视口内的要素）

// err- 错误的使用方式
// function addRiver_bbox() {
//   riverLayer = new VectorLayer({
//     source: new VectorSource({
//       format: new GeoJSON({
//         dataProjection: "EPSG:4547",
//         featureProjection: "EPSG:4326",
//       }),
//       url: "src/assets/geojson/BJ.json",
//       strategy: bboxStrategy, // 使用 bbox 策略
//     }),
//   });

//   window.map.addLayer(riverLayer);
// }

function addRiver_bbox() {
  // 读取GeoJSON数据
  riverFeatures = new GeoJSON().readFeatures(BJGrid, {
    dataProjection: "EPSG:4547",
    featureProjection: "EPSG:4326",
  });

  riverFeaturesExtent = riverFeatures.map(feature =>
    feature.getGeometry().getExtent()
  );

  riverSource = new VectorSource({
    loader: function (extent, resolution, projection, success, failure) {
      console.log("loader");
      if (lastExtent && containsExtent(lastExtent, extent)) return;
      try {
        const featuresInView = getFeaturesByExtent(extent);
        riverSource.clear();
        riverSource.addFeatures(featuresInView);
        lastExtent = extent;
        success(featuresInView);
      } catch (error) {
        riverSource.removeLoadedExtent(extent);
        failure();
      }
    },
    strategy: bboxStrategy, // 使用 bbox 策略
  });

  riverLayer = new VectorLayer({
    source: riverSource,
  });

  window.map.addLayer(riverLayer);
}

function addRiver_wfs() {
  riverSource = new VectorSource({
    format: new GeoJSON(),
    url: function (extent) {
      return (
        "http://localhost:8080/geoserver/wfs?service=WFS&" +
        "version=1.1.0&request=GetFeature&typename=BeiJiang:bj&" +
        "outputFormat=application/json&srsname=EPSG:4326&" +
        "bbox=" +
        extent.join(",") +
        ",EPSG:4326"
      );
    },
    strategy: bboxStrategy,
  });

  riverLayer = new VectorLayer({
    source: riverSource,
  });

  window.map.addLayer(riverLayer);
}

// 手动实现视口裁剪
function addRiver_manualBbox() {
  // 创建矢量图层
  riverSource = new VectorSource({
    features: [],
  });

  riverLayer = new VectorLayer({
    source: riverSource,
  });

  // 将矢量图层添加到地图
  window.map.addLayer(riverLayer);

  // 读取GeoJSON数据
  riverFeatures = new GeoJSON().readFeatures(BJGrid, {
    dataProjection: "EPSG:4547",
    featureProjection: "EPSG:4326",
  });

  riverFeaturesExtent = riverFeatures.map(feature =>
    feature.getGeometry().getExtent()
  );

  onMoveEnd();

  // 监听地图移动事件(当视口变化时，重新过滤要素)
  window.map.on("moveend", radash.debounce({ delay: 1000 }, onMoveEnd)); //使用了防抖，以减少不必要的计算
}

function onMoveEnd() {
  // 计算视口范围
  const viewExtent = getExtent(window.map);

  if (lastExtent && containsExtent(lastExtent, viewExtent)) return;

  // 过滤出在视口内的要素
  const featuresInView = getFeaturesByExtent(viewExtent);

  // 清空原有要素，添加在视口内的要素
  riverSource.clear();
  riverSource.addFeatures(featuresInView);

  lastExtent = viewExtent;
}

// 过滤出在视口内的要素
function getFeaturesByExtent(extent) {
  const featuresInView = [];
  const { length } = riverFeatures;
  let index = length;

  while (index--) {
    const feature = riverFeatures[index];
    const polygonExtent = riverFeaturesExtent[index];
    if (containsExtent(extent, polygonExtent)) {
      featuresInView.push(feature);
    }
  }

  return featuresInView;
}
</script>

<style lang="less" scoped>
#mapContainer {
  width: 100%;
  height: 99vh;
}

.panel {
  position: fixed;
  top: 10px;
  left: 150px;
  z-index: 9999;
}

.time-bar {
  .show-index {
    margin: 10px, 0;

    font-weight: bold;
    font-size: 20px;
    color: red;
    &.active {
      color: green;
    }
  }
}
</style>
